#include "VSShaderFunction.h"
#include "VSMaterial.h"
#include "VSShaderStringFactory.h"
#include "VSGraphicInclude.h"
#include "VSStream.h"
using namespace VSEngine2;
IMPLEMENT_RTTI_NoCreateFun(VSShaderFunction,VSObject)
IMPLEMENT_INITIAL_NO_CLASS_FACTORY_BEGIN(VSShaderFunction)
IMPLEMENT_INITIAL_NO_CLASS_FACTORY_END
BEGIN_ADD_PROPERTY(VSShaderFunction,VSObject)
REGISTER_PROPERTY(m_ShowName,ShowName,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_pOwner,Owner,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_pInput,Input,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_pOutput,Output,VSProperty::F_SAVE_LOAD_CLONE)
END_ADD_PROPERTY
VSShaderFunction::VSShaderFunction()
{
	m_pInput.Clear();
	m_pOutput.Clear();
	m_bIsVisited = 0;
	m_pOwner = NULL;
}
VSShaderFunction::VSShaderFunction(const VSUsedName & ShowName,VSMaterial * pMaterial)
{
	m_ShowName = ShowName;
	m_pInput.Clear();
	m_pOutput.Clear();
	VSMAC_ASSERT(pMaterial);
	m_pOwner = pMaterial;
	m_pOwner->AddShaderFuntion(this);
}
VSShaderFunction::~VSShaderFunction()
{
	for(unsigned int i = 0 ; i < m_pInput.GetNum() ; i++)
	{
		VSMAC_DELETE(m_pInput[i]);
	}
	for(unsigned int i = 0 ; i < m_pOutput.GetNum() ; i++)
	{
		VSMAC_DELETE(m_pOutput[i]);
	}
	m_pOwner->DeleteShaderFuntion(this);
}
unsigned int VSShaderFunction::DiskUse()const
{
	unsigned int Use = VSObject::DiskUse();
	Use += m_ShowName.DiskUse();
	Use += sizeof(VSMaterial *);
	Use += sizeof(unsigned int) * 2;
	Use += sizeof(VSInputNode *) * m_pInput.GetNum();
	Use += sizeof(VSOutputNode *) * m_pOutput.GetNum();
	return Use;

}
bool VSShaderFunction::Save(VSStream & rStream,unsigned int &iSaveUse)const
{
	if(!VSObject::Save(rStream,iSaveUse))
		return false;

	m_ShowName.Save(rStream,iSaveUse);

// 	if(!rStream.Write(&m_pOwner,sizeof(VSMaterial *)))
// 		return 0;
	if(!rStream.WriteObjectPtr(m_pOwner))
		return 0;
	iSaveUse += sizeof(VSMaterial *);

	unsigned int uiInputNum = m_pInput.GetNum();
	if(!rStream.Write(&uiInputNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	unsigned int uiOutputNum = m_pOutput.GetNum();
	if(!rStream.Write(&uiOutputNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	for(unsigned int i = 0 ; i < uiInputNum ; i++)
	{
// 		VSInputNode * pInputNode = m_pInput[i];
// 		if(!rStream.Write(&pInputNode,sizeof(VSInputNode *)))
// 			return 0;
		if(!rStream.WriteObjectPtr(m_pInput[i]))
			return 0;
		iSaveUse += sizeof(VSInputNode *);
	}

	for(unsigned int i = 0 ; i < uiOutputNum ; i++)
	{
// 		VSOutputNode * pOutputNode = m_pOutput[i];
// 		if(!rStream.Write(&pOutputNode,sizeof(VSOutputNode *)))
// 			return 0;
		if(!rStream.WriteObjectPtr(m_pOutput[i]))
			return 0;
		iSaveUse += sizeof(VSOutputNode *);
	}
	return 1;
}
bool VSShaderFunction::Load(VSStream & rStream,unsigned int &iSaveUse)
{

	if(!VSObject::Load(rStream,iSaveUse))
		return false;

	m_ShowName.Load(rStream,iSaveUse);

// 	VSMaterial * pOwner = NULL;
// 	if(!rStream.Read(&pOwner,sizeof(VSMaterial *)))
// 		return 0;
// 	AddLink(pOwner);
	if(!rStream.ReadObjectPtr(m_pOwner))
		return 0;
	iSaveUse += sizeof(VSMaterial *);

	unsigned int uiInputNum;
	if(!rStream.Read(&uiInputNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	unsigned int uiOutputNum;
	if(!rStream.Read(&uiOutputNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	m_pInput.SetBufferNum(uiInputNum);
	for(unsigned int i = 0 ; i < uiInputNum ; i++)
	{
// 		VSInputNode * pPutNode = NULL;
// 		if(!rStream.Read(&pPutNode,sizeof(VSInputNode *)))
// 			return 0;
// 		AddLink(pPutNode);
		if(!rStream.ReadObjectPtr(m_pInput[i]))
			return 0;
		iSaveUse += sizeof(VSInputNode *);
	}

	m_pOutput.SetBufferNum(uiOutputNum);
	for(unsigned int i = 0 ; i < uiOutputNum ; i++)
	{
// 		VSOutputNode * pPutNode = NULL;
// 		if(!rStream.Read(&pPutNode,sizeof(VSOutputNode *)))
// 			return 0;
// 		AddLink(pPutNode);
		if(!rStream.ReadObjectPtr(m_pOutput[i]))
			return 0;
		iSaveUse += sizeof(VSOutputNode *);
	}
	return 1;
}
bool VSShaderFunction::Clone(const VSObject *pObject,unsigned int uiType)
{
	//NO USE
	const VSShaderFunction* Temp = DynamicCast<VSShaderFunction>(pObject); 
	if(!Temp)
		return 0;
	if(VSObject::Clone(pObject,uiType))
	{
		m_ShowName = Temp->m_ShowName;
		m_pInput.Clear();
		m_pInput.SetBufferNum(Temp->m_pInput.GetNum());
		for (unsigned int i = 0 ; i < m_pInput.GetNum() ; i++)
		{
			VSInputNode * pTemp1  = Temp->m_pInput[i];
			VSInputNode * pTemp2 =(VSInputNode *)VSObject::GetInstance((pTemp1)->GetType().GetName());
			pTemp2->Clone(pTemp1,uiType);
			m_pInput[i] = pTemp2;	
			((VSPutNode *)pTemp2)->SetOwner(this);
		}

		m_pOutput.Clear();
		m_pOutput.SetBufferNum(Temp->m_pOutput.GetNum());
		for (unsigned int i = 0 ; i < m_pOutput.GetNum() ; i++)
		{
			VSOutputNode * pTemp1  = Temp->m_pOutput[i];
			VSOutputNode * pTemp2 =(VSOutputNode *)VSObject::GetInstance((pTemp1)->GetType().GetName());
			pTemp2->Clone(pTemp1,uiType);
			m_pOutput[i] = pTemp2;	
			((VSPutNode *)pTemp2)->SetOwner(this);
		}
		m_pOwner = Temp->m_pOwner;
		return 1;
	}
	else
	{
		return 0;

	}
}
void VSShaderFunction::AddAllPutNodeTo(VSArray<VSPutNode *>& LinkArray)
{
	for (unsigned int i = 0 ; i < m_pInput.GetNum() ; i++)
	{
		
		LinkArray.AddElement(m_pInput[i]);	
	}

	for (unsigned int i = 0 ; i < m_pOutput.GetNum() ; i++)
	{

		LinkArray.AddElement(m_pOutput[i]);	
	}	
}
bool VSShaderFunction::Link(const VSArray<VSPutNode *>& OldLink,const VSArray<VSPutNode *>& NewLink)
{
	for (unsigned int i = 0 ; i < m_pInput.GetNum() ; i++)
	{

		if(!m_pInput[i]->Link(OldLink,NewLink))
			return 0;
	}

	for (unsigned int i = 0 ; i < m_pOutput.GetNum() ; i++)
	{

		if(!m_pOutput[i]->Link(OldLink,NewLink))
			return 0;
	}	
	return 1;
}
bool VSShaderFunction::Register(VSStream & rStream)const
{
	if (rStream.IsObjectRegister(this))
	{
		return 1;
	}
	if(!VSObject::Register(rStream))
		return 0;

	if(!m_pOwner->Register(rStream))
		return 0;
	for(unsigned int i = 0 ; i < m_pInput.GetNum() ; i++)
	{
		if(!m_pInput[i]->Register(rStream))
			return 0;
	}

	for(unsigned int i = 0 ; i < m_pOutput.GetNum() ;i++)
	{
		if(!m_pOutput[i]->Register(rStream))
			return 0;
	}
	return 1;

}
bool VSShaderFunction::Link(VSStream & rStream)
{
	if(!VSObject::Link(rStream))
		return 0;

	//m_pOwner = (VSMaterial *)rStream.GetMapValue(GetNextLink());
	rStream.LinkObjectPtr(m_pOwner);
	for(unsigned int i = 0 ; i < m_pInput.GetNum() ; i++)
	{
		//m_pInput[i] = (VSInputNode *)rStream.GetMapValue(GetNextLink());
		rStream.LinkObjectPtr(m_pInput[i]);
	}

	for(unsigned int i = 0 ; i < m_pOutput.GetNum() ;i++)
	{
		//m_pOutput[i] = (VSOutputNode *)rStream.GetMapValue(GetNextLink());
		rStream.LinkObjectPtr(m_pOutput[i]);
	}

	return 1;
}
bool VSShaderFunction::GetInputValueString(VSString &OutString)const
{
	if(!VSRenderer::ms_pRenderer)
		return 0;
	VSString Temp;
	for(unsigned int i = 0 ; i < m_pInput.GetNum() ; i++)
	{
		
		if(m_pInput[i]->GetValueType() == VSPutNode::VT_1)
		{
			OutString +=VSRenderer::ms_pRenderer->Float() + _T(" ");/*_T("float ");*/
			Temp = VSRenderer::ms_pRenderer->FloatConst(_T("0"));
		}
		else if(m_pInput[i]->GetValueType() == VSPutNode::VT_2)
		{
			OutString +=VSRenderer::ms_pRenderer->Float2() + _T(" ");/*_T("float2 ");*/
			Temp = VSRenderer::ms_pRenderer->Float2Const(_T("0"),_T("0"));/*_T("float2(0,0)");*/
		}
		else if(m_pInput[i]->GetValueType() == VSPutNode::VT_3)
		{
			OutString +=VSRenderer::ms_pRenderer->Float3() + _T(" ");/*_T("float3 ");*/
			Temp = VSRenderer::ms_pRenderer->Float3Const(_T("0"),_T("0"),_T("0"));/*_T("float3(0,0,0)");*/
		}
		else if(m_pInput[i]->GetValueType() == VSPutNode::VT_4)
		{
			OutString +=VSRenderer::ms_pRenderer->Float4() + _T(" ");/*_T("float4 ");*/
			Temp = VSRenderer::ms_pRenderer->Float4Const(_T("0"),_T("0"),_T("0"),_T("1"));/*_T("float4(0,0,0,1)");*/
		}
		else
			return 0;
		if(!m_pInput[i]->GetOutputLink())
		{
			OutString += m_pInput[i]->GetNodeName().GetString() + _T(" = ") + Temp + _T(";\n");
			continue;
		}
// 		if(m_pInput[i]->GetValueType() != m_pInput[i]->GetOutputLink()->GetValueType())
// 			return 0;
		OutString += GetValueEqualString(m_pInput[i]->GetOutputLink(),m_pInput[i]);/*m_pInput[i]->GetNodeName() + _T(" = ") + m_pInput[i]->GetOutputLink()->GetNodeName() + _T(";\n");*/
	}
	return 1;
}
VSString VSShaderFunction::GetValueEqualString(const VSOutputNode * pOutPutNode,const VSInputNode * pInputNode)const
{
	if(!pInputNode || !pOutPutNode)
		return VSString();
	unsigned int uiMaxElement = pInputNode->GetValueType();
	if(uiMaxElement == pOutPutNode->GetValueType())
	{
		
		return pInputNode->GetNodeName().GetString() + _T(" = ") + pOutPutNode->GetNodeName().GetString() + _T(";\n");
	}
	
	VSString OutString;
	OutString = pInputNode->GetNodeName().GetString() + _T(" = ");
	VSString Value[4];
	unsigned int Mask[4];
	Mask[0] = VSRenderer::VE_R;
	Mask[1] = VSRenderer::VE_G;
	Mask[2] = VSRenderer::VE_B;
	Mask[3] = VSRenderer::VE_A;
	for(unsigned int i = 0 ; i < 4 ; i ++)
	{
		if ( i > pOutPutNode->GetValueType())
		{
			Value[i] = VSRenderer::ms_pRenderer->GetValueElement(pOutPutNode,Mask[pOutPutNode->GetValueType()]);
		}
		else
		{
			Value[i] = VSRenderer::ms_pRenderer->GetValueElement(pOutPutNode,Mask[i]);
		}

	}
	if (pInputNode->GetValueType() == VSPutNode::VT_1)
	{
		OutString +=VSRenderer::ms_pRenderer->FloatConst(Value[0]);
	}
	else if (pInputNode->GetValueType() == VSPutNode::VT_2)
	{
		OutString +=VSRenderer::ms_pRenderer->Float2Const(Value[0],Value[1]);
	}
	else if (pInputNode->GetValueType() == VSPutNode::VT_3)
	{
		OutString +=VSRenderer::ms_pRenderer->Float3Const(Value[0],Value[1],Value[2]);
	}
	else if (pInputNode->GetValueType() == VSPutNode::VT_4)
	{
		OutString +=VSRenderer::ms_pRenderer->Float4Const(Value[0],Value[1],Value[2],Value[3]);
	}
	else
		return VSString();
	OutString += _T(";\n");
	return OutString;
}
bool VSShaderFunction::GetOutPutValueString(VSString &OutString)const
{
	if(!VSRenderer::ms_pRenderer)
		return 0;
	for(unsigned int i = 0 ; i < m_pOutput.GetNum() ; i++)
	{

		if(m_pOutput[i]->GetValueType() == VSPutNode::VT_1)
		{
			OutString +=VSRenderer::ms_pRenderer->Float() + _T(" ");/*_T("float ");*/
		}
		else if(m_pOutput[i]->GetValueType() == VSPutNode::VT_2)
		{
			OutString +=VSRenderer::ms_pRenderer->Float2() + _T(" ");/*_T("float2 ")*/;
		}
		else if(m_pOutput[i]->GetValueType() == VSPutNode::VT_3)
		{
			OutString +=VSRenderer::ms_pRenderer->Float3() + _T(" ");/*_T("float3 ");*/
		}
		else if(m_pOutput[i]->GetValueType() == VSPutNode::VT_4)
		{
			OutString +=VSRenderer::ms_pRenderer->Float4() + _T(" ");/*_T("float4 ");*/
		}
		else
			return 0;

		OutString += m_pOutput[i]->GetNodeName().GetString() + _T(";\n");
	}
	return 1;
}
bool VSShaderFunction::GetShaderTreeString(VSString &OutString)
{
	if(m_bIsVisited == 1)
		return 1;
	else
	{
		m_bIsVisited = 1;
		for(unsigned int i = 0 ; i < m_pInput.GetNum(); i++)
		{
			if(m_pInput[i]->GetOutputLink() == NULL)
				continue;
			else
			{
				((VSShaderFunction *)m_pInput[i]->GetOutputLink()->GetOwner())->GetShaderTreeString(OutString);
			
			}
		
		}
		if(!GetInputValueString(OutString))
			return 0;
		if(!GetOutPutValueString(OutString))
			return 0;
		if(!GetFuntionString(OutString))
			return 0;
		return 1;
	}
}
bool VSShaderFunction::ClearShaderTreeStringFlag()
{
	if(m_bIsVisited == 0)
		return 1;
	else
	{
		m_bIsVisited = 0;
		for(unsigned int i = 0 ; i < m_pInput.GetNum(); i++)
		{
			if(m_pInput[i]->GetOutputLink() == NULL)
				continue;
			else
			{
				((VSShaderFunction *)m_pInput[i]->GetOutputLink()->GetOwner())->ClearShaderTreeStringFlag();

			}

		}
		return 1;
	}
}
VSInputNode * VSShaderFunction::GetInputNode(unsigned int uiNodeID)const
{
	if(uiNodeID >=m_pInput.GetNum())
		return NULL;
	return m_pInput[uiNodeID];
}
VSInputNode * VSShaderFunction::GetInputNode(const VSString & NodeName)const
{
	for (unsigned int i  =0 ; i < m_pInput.GetNum(); i++)
	{
		if(m_pInput[i]->GetNodeName() == NodeName)
			return m_pInput[i];
	}
	return NULL;
}

VSOutputNode * VSShaderFunction::GetOutputNode(unsigned int uiNodeID)const
{
	if(uiNodeID >=m_pOutput.GetNum())
		return NULL;
	return m_pOutput[uiNodeID];
}
VSOutputNode * VSShaderFunction::GetOutputNode(const VSString & NodeName)const
{
	for (unsigned int i  =0 ; i < m_pInput.GetNum(); i++)
	{
		if(m_pOutput[i]->GetNodeName() == NodeName)
			return m_pOutput[i];
	}
	return NULL;
}